﻿Imports System
Imports System.Management
Imports System.ServiceProcess
Imports System.Diagnostics
Public Class frmMain

    Private Declare Function ShellExecute Lib "shell32.dll" _
        Alias "ShellExecuteA" _
        (ByVal hwnd As Long, _
        ByVal lpOperation As String, _
        ByVal lpFile As String, _
        ByVal lpParameters As String, _
        ByVal lpDirectory As String, _
        ByVal nShowCmd As Long) As Long

    
    Private Const SW_SHOWNORMAL = 1
    Private Const SW_HIDE = 0

    Private Const LVSI_TUNNEL_STATUS = 1
    Private Const LVSI_TUNNEL_PEER = 2
    Private Const LVSI_TUNNEL_INTERFACE = 3
    Private Const LVSI_TUNNEL_IPADDRESS = 4
    Private Const LVSI_TUNNEL_SUBNETMASK = 5
    Private Const LVSI_TUNNEL_DHCPSERVER = 6

    Private Service As ServiceController
    Private ServiceIsInstalled As Boolean = False
    Private WithEvents Config As New OpenVPNWinSvc.Library.OpenVPNConfiguration
    Private WithEvents Stats As New OpenVPNWinSvc.Library.OpenVPNStatus


    Private Sub frmMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        ' obtain svc reference
        Try
            Service = GetSvcReference()
            Call CheckService()
            tmrServiceCheck.Enabled = True
            lsvTunnels.Items.Clear()
            Config.NoLog = True
            Config.InitializeConfig()
            Config.ReadConfiguration()
            lblNoTunnels.Visible = (lsvTunnels.Items.Count = 0)
        Catch ex As Exception
            MsgBox("frmMain_Load(): " & ex.Message, vbCritical Or vbOKOnly, "Control Panel - OpenVPN Service for Windows")
            End
        End Try
    End Sub

    Private Sub Reread()
        lsvTunnels.Items.Clear()
        Config.ReadConfiguration()
        lblNoTunnels.Visible = (lsvTunnels.Items.Count = 0)
        Call SetEditKeys()
    End Sub

    Private Function GetSvcReference() As ServiceController
        ' obtain permission
        Dim scp As New ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "OpenVPNWinSvc")
        scp.Assert()
        Dim svc As New ServiceController("OpenVPNWinSvc", Environment.MachineName)
        Return svc

        'For Each svc In ServiceController.GetServices
        '    If LCase(svc.ServiceName) = LCase("OpenVPNWinSvc") Then
        '        svc.Refresh()
        '        Return svc
        '    End If
        'Next
        'Return Nothing



    End Function


    Private Sub CheckService()
        Static LastStatus As System.ServiceProcess.ServiceControllerStatus
        Service = GetSvcReference()
        If Not Service Is Nothing Then
            Try
                If LCase(Service.ServiceName) = LCase("OpenVPNWinSvc") Then
                    Select Case Service.Status
                        Case ServiceControllerStatus.Stopped
                            btnSvcStartStop.Enabled = True
                            btnSvcRestart.Enabled = False
                            btnSvcRestart.Image = DirectCast(OpenVPNWinSvc.GUI.My.Resources.Resources.ResourceManager.GetObject("restart_disabled"), Image)
                            btnSvcStartStop.Image = DirectCast(OpenVPNWinSvc.GUI.My.Resources.Resources.ResourceManager.GetObject("start2"), Image)
                        Case ServiceControllerStatus.Running
                            If Not Service.Status = LastStatus Then
                                lsvTunnels.Items.Clear()
                                Config.ReadConfiguration()
                                LastStatus = Service.Status
                            End If
                            btnSvcStartStop.Enabled = True
                            btnSvcRestart.Enabled = True
                            btnSvcRestart.Image = DirectCast(OpenVPNWinSvc.GUI.My.Resources.Resources.ResourceManager.GetObject("restart3"), Image)
                            btnSvcStartStop.Image = DirectCast(OpenVPNWinSvc.GUI.My.Resources.Resources.ResourceManager.GetObject("stop"), Image)
                        Case Else
                            lblServiceStatus.Text = Service.Status.ToString
                    End Select
                    lblServiceStatus.Text = Service.Status.ToString
                    ServiceIsInstalled = True
                End If
            Catch ex As Exception
                lblServiceStatus.Text = "Service not installed."
                btnSvcRestart.Enabled = False
                btnSvcStartStop.Enabled = False
                ServiceIsInstalled = False
                LastStatus = Nothing
            End Try
        Else
            lblServiceStatus.Text = "Service not installed."
            btnSvcRestart.Enabled = False
            btnSvcStartStop.Enabled = False
            ServiceIsInstalled = False
        End If
    End Sub

    Private Sub ReadStatus()
        Stats.ReadStatus()
    End Sub

    Protected Overrides Sub Finalize()
        tmrServiceCheck.Stop()
        MyBase.Finalize()
    End Sub

    Private Sub tmrServiceCheck_Tick(sender As Object, e As System.EventArgs) Handles tmrServiceCheck.Tick
        Call CheckService()
        Call ReadStatus()
    End Sub

    Private Sub btnSvcStartStop_Click(sender As System.Object, e As System.EventArgs) Handles btnSvcStartStop.Click
        Select Case Service.Status
            Case ServiceControllerStatus.Stopped
                Try
                    Service.Start()
                Catch ex As InvalidOperationException
                    MsgBox("Could not start service: " & ex.InnerException.Message, MsgBoxStyle.Exclamation Or MsgBoxStyle.OkOnly)
                End Try
            Case ServiceControllerStatus.Running
                Try
                    Service.Stop()
                Catch ex As InvalidOperationException
                    MsgBox("Could not stop service: " & ex.InnerException.Message, MsgBoxStyle.Exclamation Or MsgBoxStyle.OkOnly)
                End Try
        End Select
    End Sub

    Private Sub btnSvcRestart_Click(sender As System.Object, e As System.EventArgs) Handles btnSvcRestart.Click
        If Not Service Is Nothing Then
            If Service.Status = ServiceControllerStatus.Running Then
                btnSvcStartStop.Enabled = False
                btnSvcRestart.Enabled = False
                Try
                    Service.Stop()
                    While Not Service.Status = ServiceControllerStatus.Stopped
                        Service.Refresh()
                        System.Threading.Thread.Sleep(200)
                        Application.DoEvents()
                    End While
                    System.Threading.Thread.Sleep(3000)
                    Service.Start()
                Catch ex As Exception
                    MsgBox("Could not restart service: " & ex.InnerException.Message, MsgBoxStyle.Exclamation Or MsgBoxStyle.OkOnly)
                End Try
                btnSvcRestart.Enabled = True
                btnSvcStartStop.Enabled = True
            End If
        End If
    End Sub


    Private Sub Config_CreateTunnel(TunnelName As String) Handles Config.CreateTunnel
        Dim NewItem As New ListViewItem(TunnelName)
        Dim TunInf As New cTunnelInfo
        For i As Integer = 1 To 6
            NewItem.SubItems.Add("")
        Next
        NewItem.Tag = TunInf
        lsvTunnels.Items.Add(NewItem)
    End Sub

    Private Function FindTunnelEntry(TunnelName As String) As ListViewItem
        For Each tunent As ListViewItem In lsvTunnels.Items
            If tunent.Text.ToLower = TunnelName.ToLower Then
                Return tunent
            End If
        Next
        Return Nothing
    End Function

    Private Sub Config_SetDisable(TunnelName As String) Handles Config.SetDisable
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        Dim TunInf As cTunnelInfo = DirectCast(Entry.Tag, cTunnelInfo)
        TunInf.Disabled = True
        Entry.SubItems(LVSI_TUNNEL_STATUS).Text = "Disabled"
        Entry.SubItems(LVSI_TUNNEL_PEER).Tag = ""
    End Sub



    Private Sub Stats_SetDHCPServer(TunnelName As String, NewAddress As String) Handles Stats.SetDHCPServer
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        Entry.SubItems(LVSI_TUNNEL_DHCPSERVER).Text = NewAddress
    End Sub

    Private Sub Stats_SetInterfaceID(TunnelName As String, NewID As String) Handles Stats.SetInterfaceID
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        If NewID = "" Then
            Entry.SubItems(LVSI_TUNNEL_INTERFACE).Text = ""
        Else
            Dim IntName As String = OpenVPNWinSvc.Library.NetHlp.GetAdapterDisplayNameByInterfaceID(New System.Guid(NewID))
            Entry.SubItems(LVSI_TUNNEL_INTERFACE).Text = IntName
        End If
    End Sub

    Private Sub Stats_SetIPAddress(TunnelName As String, NewAddress As String) Handles Stats.SetIPAddress
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        Entry.SubItems(LVSI_TUNNEL_IPADDRESS).Text = NewAddress
    End Sub

    Private Sub Stats_SetNetmask(TunnelName As String, NewMask As String) Handles Stats.SetNetmask
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        Entry.SubItems(LVSI_TUNNEL_SUBNETMASK).Text = NewMask
    End Sub

    Private Sub Stats_SetPeer(TunnelName As String, PeerSocket As String) Handles Stats.SetPeer
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        Entry.SubItems(LVSI_TUNNEL_PEER).Text = PeerSocket
    End Sub

    Private Sub Stats_SetStatus(TunnelName As String, NewStatus As OpenVPNWinSvc.Library.OpenVPNTunMgr.Tunnel.TunnelStatus) Handles Stats.SetStatus
        Dim Entry As ListViewItem = FindTunnelEntry(TunnelName)
        Dim TunInf As cTunnelInfo = DirectCast(Entry.Tag, cTunnelInfo)
        If TunInf.Disabled Then
            Entry.SubItems(LVSI_TUNNEL_STATUS).Text = "Disabled"
        Else
            If NewStatus = OpenVPNWinSvc.Library.OpenVPNTunMgr.Tunnel.TunnelStatus.Down Then Entry.SubItems(LVSI_TUNNEL_PEER).Text = ""
            Entry.SubItems(LVSI_TUNNEL_STATUS).Text = NewStatus.ToString
        End If
    End Sub

    Private Sub btnProperties_Click(sender As System.Object, e As System.EventArgs) Handles btnProperties.Click
        If lsvTunnels.SelectedItems.Count = 1 Then
            Dim N As New frmTunnelConfig
            N.TunnelName = lsvTunnels.SelectedItems(0).Text
            N.Reset()
            N.ShowDialog(Me)
            N = Nothing
            Reread()
        End If
    End Sub

    Private Sub lsvTunnels_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles lsvTunnels.SelectedIndexChanged
        Call SetEditKeys()
    End Sub

    Private Sub SetEditKeys()
        Select Case lsvTunnels.SelectedItems.Count
            Case 0
                btnProperties.Enabled = False
                btnRemove.Enabled = False
            Case 1
                btnProperties.Enabled = True
                btnRemove.Enabled = True
            Case Is > 1
                btnProperties.Enabled = False
                btnRemove.Enabled = True
        End Select
    End Sub

    Private Sub btnServices_Click(sender As System.Object, e As System.EventArgs) Handles btnServices.Click
        ShellExecute(CLng(Me.Handle), Microsoft.VisualBasic.vbNullString, "services.msc", Microsoft.VisualBasic.vbNullString, "C:\", SW_SHOWNORMAL)
    End Sub

    Private Sub btnEventView_Click(sender As System.Object, e As System.EventArgs) Handles btnEventView.Click
        ShellExecute(CLng(Me.Handle), Microsoft.VisualBasic.vbNullString, "eventvwr.msc", Microsoft.VisualBasic.vbNullString, "C:\", SW_SHOWNORMAL)
    End Sub

    Private Sub btnAdd_Click(sender As System.Object, e As System.EventArgs) Handles btnAdd.Click
        Try
            frmAddTunnel.TunnelName = ""
            frmAddTunnel.ShowDialog()
            If frmAddTunnel.Result = MsgBoxResult.Ok Then
                Config.NewTunnel(frmAddTunnel.TunnelName)
                Reread()
            End If
        Catch ex As Exception
            MsgBox("Unable to create tunnel: " & ex.Message)
        End Try
    End Sub

    Private Sub btnRemove_Click(sender As System.Object, e As System.EventArgs) Handles btnRemove.Click
        Dim Result As MsgBoxResult
        If lsvTunnels.SelectedItems.Count > 0 Then
            Result = MsgBox("Removing [" & lsvTunnels.SelectedItems.Count & "] tunnels." & vbCrLf & "Are you sure?", MsgBoxStyle.Question Or MsgBoxStyle.OkCancel)
            If Result = MsgBoxResult.Ok Then
                Try
                    While lsvTunnels.SelectedItems.Count > 0
                        Config.RemoveTunnel(lsvTunnels.SelectedItems(0).Text)
                        lsvTunnels.SelectedItems(0).Remove()
                    End While
                    Reread()
                Catch ex As Exception
                    MsgBox("Unable to remove tunnel: " & ex.Message)
                End Try
            End If
        End If
    End Sub

    Private Sub btnAbout_Click(sender As System.Object, e As System.EventArgs) Handles btnAbout.Click
        frmAbout.ShowDialog(Me)
    End Sub

#Region "Service Maintenance"

    Private Sub btnMaintenance_Click(sender As System.Object, e As System.EventArgs) Handles btnMaintenance.Click
        InstallServiceToolStripMenuItem.Enabled = Not ServiceIsInstalled
        UninstallServiceToolStripMenuItem.Enabled = ServiceIsInstalled
        ctmSvcMaint.Show(MousePosition)
    End Sub

    Private Sub ServiceInstall_Click(sender As System.Object, e As System.EventArgs) Handles InstallServiceToolStripMenuItem.Click
        Dim Cmd As String = "sc"
        Dim Par As String = "create OpenVPNWinSvc binpath= """ & GetAppPath() & "OpenVPNWinSvc.Service.exe"" displayname= ""OpenVPN Service for Windows"" start= ""auto"" depend= ""eventlog/dhcp/tap0901"""
        ShellExecute(CLng(Me.Handle), Microsoft.VisualBasic.vbNullString, Cmd, Par, "C:\", SW_HIDE)
        Par = "description OpenVPNWinSvc ""Establishes endpoint identity and provides secure communications over an untrusted IP network."""
        ShellExecute(CLng(Me.Handle), Microsoft.VisualBasic.vbNullString, Cmd, Par, "C:\", SW_HIDE)
    End Sub

    Private Sub ServiceUninstall_Click(sender As System.Object, e As System.EventArgs) Handles UninstallServiceToolStripMenuItem.Click
        Dim Cmd As String = "sc"
        Dim Par As String = "delete OpenVPNWinSvc"
        ShellExecute(CLng(Me.Handle), Microsoft.VisualBasic.vbNullString, Cmd, Par, "C:\", SW_HIDE)
    End Sub

    Private Sub WipeCfg_Click(sender As System.Object, e As System.EventArgs) Handles WipeConfigurationToolStripMenuItem.Click
        Dim Res As MsgBoxResult = MsgBox("Wipe service configuration: Cannot be undone." & vbCrLf & "Are you sure?", vbQuestion Or vbOKCancel)
        If Res = MsgBoxResult.Ok Then
            Dim Cfg As New OpenVPNWinSvc.Library.OpenVPNConfiguration
            Cfg.NoLog = True
            Cfg.WipeConfig()
            Cfg = Nothing
        End If
        Reread()
    End Sub

    Private Function GetAppPath() As String
        Dim path As String = Application.StartupPath
        If Not path.EndsWith("\") Then path = path & "\"
        Return path
    End Function

#End Region

End Class
